LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

-- ForwardingBuffer

-- Interfacing Stuff
-- IN  RCV_to_FWD_data (8 bits)
-- IN  RCV_to_FWD_FrameAvail (1 bit)
-- IN  RCV_to_FWD_length (12 bits)
-- OUT FWD_to_RCV_length_ACK (1 bit)
-- OUT FWD_to_RCV_frame_ACK (1 bit)

-- Intrasystem Stuff
-- IN passdata (1 bit)
-- OUT buffdata (8 bits)
-- OUT buffsize (11 bits)

--RCV sends us frame available.
--FWD sends RCV length ACK.
--RCV sends length.
--FWD has room = '1'
--FWD sends RCV frame AcK.
--RCV sends FWD frame

ENTITY ForwardingBuffer IS
   PORT(
       clr : IN STD_LOGIC;
       clk : IN STD_LOGIC;
       data_available : IN STD_LOGIC;
       pass_data	:	IN	STD_LOGIC;
       IN_RCV_to_FWD_DATA	  	  : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
	   IN_RCV_to_FWD_LENGTH  	  : IN STD_LOGIC_VECTOR(11 DOWNTO 0); --MSB is valid bit
       OUT_FWD_to_RCV_LENGTH_ACK  : OUT STD_LOGIC;
	   OUT_FWD_to_RCV_FRAME_ACK	  : OUT STD_LOGIC;
       data_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
       count_out : OUT STD_LOGIC_VECTOR(11 DOWNTO 0);
       srcAddressValid : OUT STD_LOGIC;
       desAddressValid : OUT STD_LOGIC;
       packetType : OUT STD_LOGIC;
       srcAddress : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
       desAddress : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
       sendingsrcAddress, sendingdesAddress : OUT STD_LOGIC;
       packet_size_comparator_out : OUT STD_LOGIC;
       bufferSize : OUT STD_LOGIC_VECTOR(10 DOWNTO 0);
       bufferDone : OUT STD_LOGIC; -- Can we assume we're done if we have an empty buffer?
       bufferAlmostDone : OUT STD_LOGIC;
       IPv4_frame_count, VLAN_frame_count	:	OUT STD_LOGIC_VECTOR(11 DOWNTO 0)
       );
END ForwardingBuffer;

ARCHITECTURE forwarding_buffer_arch OF ForwardingBuffer IS

COMPONENT Counter_12_bit IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		cnt_en		: IN STD_LOGIC ;
		updown		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (11 DOWNTO 0)
	);
END COMPONENT Counter_12_bit;

COMPONENT BufferFIFO IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		rdreq		: IN STD_LOGIC ;
		wrreq		: IN STD_LOGIC ;
		empty		: OUT STD_LOGIC ;
		full		: OUT STD_LOGIC ;
		q			: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
		usedw		: OUT STD_LOGIC_VECTOR (10 DOWNTO 0)
	);
END COMPONENT;

COMPONENT BufferFF IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT AddressFIFO IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		rdreq		: IN STD_LOGIC ;
		wrreq		: IN STD_LOGIC ;
		empty		: OUT STD_LOGIC ;
		full		: OUT STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
		
		-- CHANGE THIS TO 3 BITS
		
		usedw		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END COMPONENT;

COMPONENT TestFF IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT ForwardingBufferSizeShiftRegister IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (10 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		load		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (10 DOWNTO 0)
	);
END COMPONENT;


COMPONENT AddressRegister IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		load		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
	);
END COMPONENT AddressRegister;

COMPONENT OutMUXFlipFlop IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;


SIGNAL count : STD_LOGIC_VECTOR(11 DOWNTO 0);
SIGNAL BuffEmpty : STD_LOGIC; 
SIGNAL BuffFull : STD_LOGIC;
SIGNAL BuffLength: STD_LOGIC_VECTOR(10 DOWNTO 0);
SIGNAL Add0Empty : STD_LOGIC; 
SIGNAL Add0Full : STD_LOGIC;
SIGNAL Add0Length: STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL Add1Empty : STD_LOGIC; 
SIGNAL Add1Full : STD_LOGIC;
SIGNAL Add1Length: STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL srcAddressBB: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL desAddressBB: STD_LOGIC_VECTOR(7 DOWNTO 0);

SIGNAL IreadtheLength : STD_LOGIC;
SIGNAL theLength : STD_LOGIC_VECTOR(11 DOWNTO 0);

SIGNAL des0 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL des1 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL des2 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL des3 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL des4 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL des5 : STD_LOGIC_VECTOR(7 DOWNTO 0);

SIGNAL src0 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL src1 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL src2 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL src3 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL src4 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL src5 : STD_LOGIC_VECTOR(7 DOWNTO 0);

SIGNAL srcAddressBuilder : STD_LOGIC_VECTOR(47 DOWNTO 0);
SIGNAL desAddressBuilder : STD_LOGIC_VECTOR(47 DOWNTO 0);

SIGNAL shutoffsrcAddress : STD_LOGIC;
SIGNAL shutoffdesAddress : STD_LOGIC;

SIGNAL count_is_14	:	STD_LOGIC; --000000001110
SIGNAL count_is_15	:	STD_LOGIC; --000000001111
SIGNAL count_is_16	:	STD_LOGIC; --000000010000
SIGNAL count_is_17	:	STD_LOGIC; --000000010001
SIGNAL count_is_18	:	STD_LOGIC; --000000010010
SIGNAL count_is_19	:	STD_LOGIC; --000000010011
SIGNAL count_is_20  : STD_LOGIC;
SIGNAL count_is_21 : STD_LOGIC;

SIGNAL count_is_0	:	STD_LOGIC; --000000001000
SIGNAL count_is_1	:	STD_LOGIC; --000000001001
SIGNAL count_is_2	:	STD_LOGIC; --000000001010
SIGNAL count_is_3	:	STD_LOGIC; --000000001011
SIGNAL count_is_4	:	STD_LOGIC; --000000001100
SIGNAL count_is_5	:	STD_LOGIC; --000000001101

SIGNAL count_is_6	:	STD_LOGIC; --000000001000
SIGNAL count_is_7	:	STD_LOGIC; --000000001001

SIGNAL count_is_8	:	STD_LOGIC; --000000001000
SIGNAL count_is_9	:	STD_LOGIC; --000000001001
SIGNAL count_is_10	:	STD_LOGIC; --000000001010
SIGNAL count_is_11	:	STD_LOGIC; --000000001011
SIGNAL count_is_12	:	STD_LOGIC; --000000001100
SIGNAL count_is_13	:	STD_LOGIC; --000000001101

SIGNAL srcAddressValidSignal, desAddressValidSignal : STD_LOGIC;


SIGNAL fifo_start, fifo_send	:	STD_LOGIC;


SIGNAL packet_size_comparator	:	STD_LOGIC;
SIGNAL OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL : STD_LOGIC;
SIGNAL packetSize : STD_LOGIC_VECTOR (10 DOWNTO 0);
SIGNAL currentlyReadingData : STD_LOGIC;
SIGNAL dropfromtwo : STD_LOGIC;
--SIGNAL currentCountOut : STD_LOGIC_VECTOR(11 DOWNTO 0);
--SIGNAL lastByteofFrame : STD_LOGIC;
SIGNAL IReadLength : STD_LOGIC;
SIGNAL bufferisDone : STD_LOGIC;

SIGNAL count_of_all_frames,count_of_IPv4_frames, count_of_VLAN_frames	:	STD_LOGIC;
SIGNAL packetType_en:	STD_LOGIC;
--SIGNAL IPv4_frame_count, VLAN_frame_count : STD_LOGIC_VECTOR(11 DOWNTO 0);
SIGNAL length_to_XMT : STD_LOGIC_VECTOR (10 DOWNTO 0);
BEGIN

count_out <= count;

--lastByteofFrame <= (((currentCountOut(0) AND packetSize(0)) OR (NOT(currentCountOut(0)) AND NOT(packetSize(0))))
--AND ((currentCountOut(1) AND packetSize(1)) OR (NOT(currentCountOut(1)) AND NOT(packetSize(1))))
--AND ((currentCountOut(2) AND packetSize(2)) OR (NOT(currentCountOut(2)) AND NOT(packetSize(2))))
--AND ((currentCountOut(3) AND packetSize(3)) OR (NOT(currentCountOut(3)) AND NOT(packetSize(3))))
--AND ((currentCountOut(4) AND packetSize(4)) OR (NOT(currentCountOut(4)) AND NOT(packetSize(4))))
--AND ((currentCountOut(5) AND packetSize(5)) OR (NOT(currentCountOut(5)) AND NOT(packetSize(5))))
--AND ((currentCountOut(6) AND packetSize(6)) OR (NOT(currentCountOut(6)) AND NOT(packetSize(6))))
--AND ((currentCountOut(7) AND packetSize(7)) OR (NOT(currentCountOut(7)) AND NOT(packetSize(7))))
--AND ((currentCountOut(8) AND packetSize(8)) OR (NOT(currentCountOut(8)) AND NOT(packetSize(8))))
--AND ((currentCountOut(9) AND packetSize(9)) OR (NOT(currentCountOut(9)) AND NOT(packetSize(9))))
--AND ((currentCountOut(10) AND packetSize(10)) OR (NOT(currentCountOut(10)) AND NOT(packetSize(10))))
--);

--RCV sends us frame available. -> Latch
--FWD sends RCV length ACK. -> Response based on latch
RCVsendsusframeavailable: TestFF PORT MAP (clr, clk, (data_available AND NOT(IReadLength) AND (bufferisDone)), OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL);
OnlyRequestLengthOnce: TestFF PORT MAP (clr, (OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL OR NOT(data_available)), OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL, IReadLength);
OUT_FWD_to_RCV_LENGTH_ACK <= OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL;
--OUT_RCV_to_FWD_DATA <= IN_RCV_to_FWD_DATA;
--out_data_available <= data_available;

IreadtheLength <= IReadLength; 
length_to_XMT<=IN_RCV_to_FWD_LENGTH(10 DOWNTO 0);
--RCVsendsuslength: ForwardingBufferSizeShiftRegister PORT MAP (clr, clk, IN_RCV_to_FWD_LENGTH(10 DOWNTO 0), (OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL), '1', packetSize);
-- EDIT - This is done so we don't have to input a size
RCVsendsuslength: ForwardingBufferSizeShiftRegister PORT MAP (clr, clk, length_to_XMT, OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL,  OUT_FWD_to_RCV_LENGTH_ACK_SIGNAL , packetSize);

theLength(10 DOWNTO 0) <= packetSize;

bufferSize <= packetSize(10 DOWNTO 0);
--out_clk <= clk;
--out_clr <= clr;
--pass_out_data <= pass_data;

-- Request data after you've checked data length and data is available
NowReceivingData: TestFF PORT MAP (clr, clk, ((data_available AND IReadLength)), currentlyReadingData);

OUT_FWD_to_RCV_FRAME_ACK <= currentlyReadingData;


--COMPONENT Counter_12_bit IS
--	PORT
--	(
--		aclr		: IN STD_LOGIC ;
--		clock		: IN STD_LOGIC ;
--		cnt_en		: IN STD_LOGIC ;
--		updown		: IN STD_LOGIC ;
--		q		: OUT STD_LOGIC_VECTOR (11 DOWNTO 0)
--	);
--END COMPONENT Counter_12_bit;

	
--Counter only counts if we're reading data in.
incr_counter: Counter_12_bit PORT MAP (clr, clk, (currentlyReadingData XOR (pass_data AND (count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4) OR count(3) OR count(2) OR count(1) OR count(0)))), NOT(pass_data), count);

--COMPONENT BufferFIFO IS
--	PORT
--	(
--		aclr		: IN STD_LOGIC ;
--		clock		: IN STD_LOGIC ;
--		data		: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
--		rdreq		: IN STD_LOGIC ;
--		wrreq		: IN STD_LOGIC ;
--		empty		: OUT STD_LOGIC ;
--		full		: OUT STD_LOGIC ;
--		q			: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
--		usedw		: OUT STD_LOGIC_VECTOR (10 DOWNTO 0)
--	);
--END COMPONENT;

--ENTITY OutMUXFlipFlop IS
--	PORT
--	(
--		aclr		: IN STD_LOGIC ;
--		clock		: IN STD_LOGIC ;
--		data		: IN STD_LOGIC ;
--		enable		: IN STD_LOGIC ;
--		q		: OUT STD_LOGIC 
--	);
--END OutMUXFlipFlop;


--	--Data Buffer
go_buffer_fifo: BufferFIFO PORT MAP (clr, clk, IN_RCV_to_FWD_DATA, (pass_data AND (BuffLength(10) OR BuffLength(9) OR BuffLength(8) OR BuffLength(7) OR BuffLength(6) OR BuffLength(5) OR BuffLength(4) OR BuffLength(3) OR BuffLength(2) OR BuffLength(1) OR BuffLength(0))), currentlyReadingData, bufferisDone, BuffFull, data_out, BuffLength);
flagontwo: OutMUXFlipFlop PORT MAP (clr, clk, ((NOT(BuffLength(10) OR BuffLength(9) OR BuffLength(8) OR BuffLength(7) OR BuffLength(6) OR BuffLength(5) OR BuffLength(4) OR BuffLength(3) OR BuffLength(2) OR BuffLength(0)) AND BuffLength(1))), '1', dropfromtwo);
bufferDone <= bufferisDone;
bufferAlmostDone  <= dropfromtwo AND (NOT(BuffLength(10) OR BuffLength(9) OR BuffLength(8) OR BuffLength(7) OR BuffLength(6) OR BuffLength(5) OR BuffLength(4) OR BuffLength(3) OR BuffLength(2) OR BuffLength(1)) AND BuffLength(0));


	sendingdesAddress <= count_is_1 OR count_is_2 OR count_is_3 OR count_is_4 OR count_is_5 OR count_is_6;
	sendingsrcAddress <= count_is_7 OR count_is_8 OR count_is_9 OR count_is_10 OR count_is_11 OR count_is_12;
	srcAddress <= IN_RCV_to_FWD_DATA;
	desAddress <= IN_RCV_to_FWD_DATA;
	
	count_is_0 <= NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3) OR count(2) OR count(1) OR count(0));
	count_is_1 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3) OR count(2) OR count(1)) AND count(0));
	count_is_2 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3) OR count(2) OR count(0)) AND count(1));
	count_is_3 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3) OR count(2)) AND count(1) AND count(0));
	count_is_4 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3) OR count(0) OR count(1)) AND count(2));
	count_is_5 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3) OR count(1)) AND count(2) AND count(0));
	count_is_6 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3) OR count(0)) AND count(2) AND count(1));
	count_is_7 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(3)) AND count(2) AND count(1) AND count(0));
	count_is_8 <= NOT (count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)) AND count(3) 
					AND NOT (count(2) OR count(1) OR count(0));
	count_is_9 <= NOT (count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)) AND count(3) 
					AND NOT (count(2) OR count(1)) AND count(0);
	count_is_10 <= NOT (count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)) AND count(3) 
					AND NOT (count(2) OR count(0)) AND count(1);
	count_is_11 <= NOT (count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)) AND count(3) 
					AND (NOT(count(2))) AND count(1) AND count(0);	
    count_is_12 <= (NOT(count(11) OR count(10) OR count(9) OR count(8) OR count(7) OR count(6) OR count(5) OR count(4)
					OR count(1) OR count(0)) AND count(3) AND count(2));
    --srcAddressValidSignal <= (NOT(clr)) AND ((data_available)AND((count(2) AND count(1) AND NOT(count(0)))OR(srcAddressValidSignal)));
    --desAddressValidSignal <= (NOT(clr))AND(data_available)AND((count(3) AND count(2) AND NOT(count(1) OR count(0)))OR(desAddressValidSignal));


--	isSrcAddressValid: TestFF PORT MAP ((clr OR (NOT(data_available))), clk, ( count_is_11), srcAddressValidSignal);
--	isDesAddressValid: TestFF PORT MAP ((clr OR (NOT(data_available))), clk, ( count_is_5), desAddressValidSignal);

	isSrcAddressValid: BufferFF PORT MAP (clr OR bufferisDone , clk, count_is_12, NOT(srcAddressValidSignal), srcAddressValidSignal);
	isDesAddressValid: BufferFF PORT MAP (clr OR bufferisDone, clk, count_is_6, NOT(desAddressValidSignal), desAddressValidSignal);
	
 
    srcAddressValid <= srcAddressValidSignal;
    desAddressValid <= desAddressValidSignal;
   
    fifo_start <= currentlyReadingData AND NOT IN_RCV_to_FWD_LENGTH(11);
    fifo_send <= pass_data;

	count_of_IPv4_frames <= NOT IN_RCV_to_FWD_LENGTH(11) AND NOT(IN_RCV_to_FWD_LENGTH(10) AND NOT IN_RCV_to_FWD_LENGTH(9)AND NOT 
															 IN_RCV_to_FWD_LENGTH(8) AND IN_RCV_to_FWD_LENGTH(7) AND NOT 
															 IN_RCV_to_FWD_LENGTH(6) AND NOT IN_RCV_to_FWD_LENGTH(5) AND NOT 
															 IN_RCV_to_FWD_LENGTH(4) AND NOT IN_RCV_to_FWD_LENGTH(3)AND NOT 
															 IN_RCV_to_FWD_LENGTH(2) AND NOT IN_RCV_to_FWD_LENGTH(1) AND NOT 
															 IN_RCV_to_FWD_LENGTH(0)); --0x800 = 0b100000000000
	count_of_VLAN_frames <= IN_RCV_to_FWD_LENGTH(11) AND NOT(IN_RCV_to_FWD_LENGTH(10) AND NOT IN_RCV_to_FWD_LENGTH(9) AND NOT 
															 IN_RCV_to_FWD_LENGTH(8) AND NOT IN_RCV_to_FWD_LENGTH(7) AND NOT 
															 IN_RCV_to_FWD_LENGTH(6) AND NOT IN_RCV_to_FWD_LENGTH(5)) 
													 AND IN_RCV_to_FWD_LENGTH(4) 
													 AND NOT (IN_RCV_to_FWD_LENGTH(3) AND NOT IN_RCV_to_FWD_LENGTH(2) AND NOT 
															  IN_RCV_to_FWD_LENGTH(1) AND NOT IN_RCV_to_FWD_LENGTH(0)); --0x810 = 0b100000010000
	 
	packetType<= (NOT count_of_IPv4_frames) AND count_of_VLAN_frames;											  
    packetType_en<=(NOT count_of_IPv4_frames) AND count_of_VLAN_frames;
    
    IPv4_counter: Counter_12_bit PORT MAP ( clr , clk, NOT packetType_en, '1', IPv4_frame_count);
    VLAN_counter: Counter_12_bit PORT MAP ( clr  , clk,  packetType_en, '1', VLAN_frame_count);

END forwarding_buffer_arch;